Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: Sor's Bot Scoreboard - player name question

  1. #1

    Default Sor's Bot Scoreboard - player name question

    Hi again!

    Thanks to you guys for the help on my previous jv_bot topic.

    If someone could help me out again it would be great?!. I am stuck with a problem on Sor's old BOT Scoreboard. Again, scripting is not my forte….

    Currently running 1.11 stock on an off-site server, ironing out problems before coming up to Reborn. I have this pk3 on both server and client end.
    Files attached. (I have not edited any files).

    Issue:
    When I join a match, the bot scoreboard kicks in, however, unless the server name's "player name" is set, the scoreboard is blank where my player name should be.

    To clarify, when I join the match I appear all ok on the "regular killboard" as “Oh_Gaz”.
    If I do a “server console status” check, I am client ID “0”.
    However under Sor’s Bot scoreboard my name is “Blank”. (see pic below).

    Click image for larger version. 

Name:	Scoreboarderror.jpg 
Views:	23 
Size:	63.3 KB 
ID:	1295

    It should have “Oh_Gaz” there.
    Now if I change the server’s player name, it works.
    That is:“RCON set name “Oh_Gaz”, then the blank position on the bot scoreboard becomes “Oh_Gaz”.
    Of course, this then means that if I disconnect and any human joins the server first, then they will be called “Oh_Gaz”.

    So it’s almost like the server is a phantom identity.
    (It’s really my activity impacting the results of that player, but the scoreboard doesn’t recognise that activity as me – just the server’s set name).

    Once a 2nd human enters, I know it becomes redundant, as everyone then just becomes “Player 0, Player 1, Player 2” etc. on the bot scoreboard with this mod.
    But I am just working off 1 player joining at the moment.

    My attention is focused on the file jv_mp_players.scr as it looks most relevant I think?. I noticed in the script there is an entry starting with:
    “/**
    Removes possibly fake player from the map. Optional.”

    Not sure if that’s related?
    Could someone check the files and this one in particular? No idea what to tweak….
    Many thanks again!

    The full code from jv_mp_players.scr :

    Code:
    /**
    Main Player Handler script for MoH:AA (t)dm/obj
    ===============================================
    by jv_map
    version 1.1
    ---------------------------------------------
    Copyright (c) 2002-2003 Jeroen Vrijkorte
    All rights reserved.
    ---------------------------------------------
    Distribution is allowed provided all subsequent 
    conditions are met:
    
    1. Commercial use is prohibited.
    
    2. The above copyright notice and this permission notice shall
    be included in all copies or substantial portions of the file.
    
    3. If you have made modifications to the original files you must
    cause the modified files to carry prominent notices stating
    that you changed the files.
    
    COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, 
    SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE 
    SOFTWARE OR DOCUMENTATION.
    ---------------------------------------------
    jv_map@planetmedalofhonor.com
    http://www.planetmedal.com/freebrief
    ---------------------------------------------
    */
    
    /**
    ---------------------------------------------
    Main Player Handler
    
    Runs threads when a player joins the game.
    ---------------------------------------------
    */
    
    /**
    Main thread. Run at startup below waittill spawn.
    
    Use level.main_player_handler_debug = 1 for verbose output.
    */
    main_player_handler:
    	if(level.main_player_handler == NIL)
    		level.main_player_handler = 0
    
    	level.main_player_handler++
    	
    	if(level.main_player_handler > 1)
    	{
    		println "INFO[jv_mp_players::main_player_handler]: Handler already running, exiting."
    		end
    	}
    	
    	waitthread reset
    
    	if(level.main_player_handler_firstplayerfix == 1)
    		$player[1] thread firstplayerbugfix 
    	
    	while(level.main_player_handler >= 1)
    	{
    		for(local.playernum = 1; local.playernum <= $player.size; local.playernum++)
    		{
    			local.player = $player[local.playernum]
    			level.player = local.player
    			if(local.player.checked != 1)
    			{
    				local.player.checked = 1
    				local.player thread child_player_handler local.playernum
    			}
    		}
    		wait 0.5
    	}
    	println "INFO[jv_mp_players::main_player_handler]: Main player handler terminated."
    end
    
    /**
    Removes possibly fake player from the map. Optional.
    
    Set level.main_player_handler_firstplayerfix = 1 
    to fix the first player bug on dedicated servers.
    */
    firstplayerbugfix:
    	if(self.dmteam == spectator)
    	{
    		println "INFO[jv_mp_players::firstplayerbugfix]: Verifying first player..."
    		local.location = self.origin
    		local.angles = self.angles
    		wait 5
    		if(self != NULL && self.dmteam == spectator && self.ingame != 1 && local.location == self.origin && local.angles == self.angles)
    		{
    			println "INFO[jv_mp_players::firstplayerbugfix]: Warning first player..."
    			local.times = 1
    			while(self != NULL && self.dmteam == spectator && self.ingame != 1 && local.times <= 10 && self.useheld == 0 && local.location == self.origin && local.angles == self.angles)
    			{
    				self iprint "Please move or hold USE"
    				wait 1
    				local.times++
    			}
    			// waited ten
    			if(self != NULL && local.times >= 10)
    			{
    				// disconnect and remove ent
    				self iprint "Disconnected, sorry"
    				println "INFO[jv_mp_players::firstplayerbugfix]: Kicked first player"
    				waitframe
    				if(self)
    					self remove
    			}
    			else
    			{
    				self iprint "Ok thanks"
    				println "INFO[jv_mp_players::firstplayerbugfix]: First player is ok"
    			}
    		}
    		else
    			println "INFO[jv_mp_players::firstplayerbugfix]: First player is ok"
    	}
    end
    
    /**
    Shutdown one main player handler request.
    */
    shutdown:
    	level.main_player_handler--
    end
    
    /**
    Shutdown main player handler regardless 
    of the number of requests.
    */
    kill:
    	level.main_player_handler = -1
    end
    
    /**
    Resets all players to 'not checked'. Internal use.
    */
    reset:
    	for(local.playernum = 1; local.playernum <= $player.size; local.playernum++)
    	{
    		local.player = $player[local.playernum]
    		local.player.checked = 0
    	}
    end
    
    /**
    Player specific thread. Internal use.
    */
    child_player_handler local.debugnum:
    	local.entnum = self.entnum
    	if(level.main_player_handler_debug)
    		println "INFO[jv_mp_players::child_player_handler]: Child handler started for player " local.debugnum " (entnum: " local.entnum ")."
    	while(level.main_player_handler >= 1 && self != NULL)
    	{
    		self.ingame = 0
    		self thread player_stage_thread 1
    		self.stage = 1
    		//--- stage 1 ---//
    		if(level.main_player_handler_debug)
    			println "INFO[jv_mp_players::child_player_handler]: Player " local.debugnum " has entered stage 1."
    			
    		while (level.main_player_handler >= 1 && self != NULL && (self.dmteam == "spectator" || !(isAlive self)))
    			wait 0.5
    		
    		if(level.main_player_handler >= 1 && self != NULL && isAlive self)
    		{
    			local.team = self.dmteam
    			//--- stage 2 ---//
    			if(level.main_player_handler_debug)
    				println "INFO[jv_mp_players::child_player_handler]: Player " local.debugnum " has entered stage 2."
    			self thread player_stage_thread 2
    			self.stage = 2
    			self waitthread player_join_game
    			//--- stage 3 ---//
    			self thread player_stage_thread 3
    			if(level.main_player_handler_debug)
    				println "INFO[jv_mp_players::child_player_handler]: Player " local.debugnum " has entered stage 3."
    			self.stage = 3
    			self.ingame = 1
    
    // ---- Bot Scoreboard ----
    			self thread setup_kill
    
    			if (self.deathcount == NIL)
    				self.deathcount = 0
    
    			local.backup_dc = self.deathcount
    // ------------------------
    			while(level.main_player_handler >= 1 && self != NULL && isAlive self && local.team == self.dmteam)
    			{
    				if (self.detect == NIL || self.detect == NULL)
    				{
    					self thread setup_kill
    				}
    					
    				wait 0.1
    			}
    		}
    		if(self != NULL && level.main_player_handler >= 1)
    		{
    			//--- stage 4 ---//
    			self thread player_stage_thread 4
    			if(level.main_player_handler_debug)
    				println "INFO[jv_mp_players::child_player_handler]: Player " local.debugnum " has entered stage 4."
    			self.stage = 4
    		}
    	}
    	if(level.main_player_handler_debug)
    		println "INFO[jv_mp_players::child_player_handler]: Child handler terminated for player " local.debugnum
    end
    
    /**
    Run all threads for the given player from the specified stage.
    
    integer stage: number of stage to run threads of.
    */
    player_stage_thread local.stage:
    	for(local.numthread = 1; local.numthread <= level.stagethread[local.stage].size; local.numthread++)
    	{
    		local.thread = level.stagethread[local.stage][local.numthread]
    		local.script = level.stagethreadscript[local.stage][local.numthread]
    		if(local.thread != NIL && local.thread != 0)
    		{
    			if(level.main_player_handler_debug == 1)
    				println "INFO[jv_mp_players::player_stage_thread]: Running thread " local.thread " (stage " local.stage ")"
    			parm.player = self
    			self testthread local.script local.thread
    		}
    		else if(local.thread != 0)
    			println "WARNING[jv_mp_players::player_stage_thread]: Invalid thread definition [thread: " local.thread ", script: " local.script "] (stage " local.stage ")"
    	}
    end
    
    /**
    Resolves string stages to stage numbers. Internal use.
    
    string stage: stage to resolve
    */
    resolve_stage local.stage:
    	local.prestage = local.stage
    	
    	switch(local.stage)
    	{
    		start:
    			local.stage = 1
    			break
    		prepare:
    			local.stage = 2
    			break
    		join:
    			local.stage = 3
    			break
    		death:
    			local.stage = 4
    	}
    	
    	if(level.main_player_handler_debug == 1 && local.prestage != local.stage)
    		println "INFO[jv_mp_players::resolve_stage]: Resolved stage " local.prestage " to stage " local.stage
    end local.stage
    
    /**
    Adds a stage thread for all players. This thread will be run 
    when a player enters the specified stage. Stages are:
    	start (1): 		player enters the game
    	prepare (2):	player joins a team
    	join (3):		player enters the game
    	death(4):		player dies -> goes to stage 3 again if respawn is enabled.
    
    Arguments are as follows:
    
    array scriptthread:	array defined as:
    	[1]: string script file.
    	[2]: string thread.
    string stage:		stage that should trigger this thread.
    boolean noresolve:	set to '1' to prevent stage resolving. Not recommended.
    */
    add_stage_thread local.scriptthread local.stage local.noresolve:
    	// usage example: waitthread global/jv_mp_players::add_stage_thread "maps/dm/mymap.scr"::start prepare
    	
    	local.stage = waitthread resolve_stage local.stage
    
    	local.thread = local.scriptthread[2]
    	if(local.thread == NIL || local.thread == NULL)
    	{
    		println "ERROR[jv_mp_players::add_stage_thread]: Invalid thread: " local.thread " for stage " local.stage
    		end
    	}
    	
    	local.script = local.scriptthread[1]
    	if(local.script == NIL || local.script == NULL)
    	{
    		if(level.script != NIL)
    		{
    			println "WARNING[jv_mp_players::add_stage_thread]: Invalid script: " local.script " for stage " local.stage ", setting to level.script (" level.script ")."
    			local.script = level.script
    		}
    		else
    		{
    			println "ERROR[jv_mp_players::add_stage_thread]: Invalid script: " local.script " for stage " local.stage "."
    			end
    		}
    	}
    	
    	local.siz = level.stagethread[local.stage].size
    	
    	if(local.siz < 0) 
    		local.siz = 0
    		
    	level.stagethread[local.stage][local.siz + 1] = local.thread
    	level.stagethreadscript[local.stage][local.siz + 1] = local.script
    	
    	println "INFO[jv_mp_players::add_stage_thread]: Added stage thread " local.script "::" local.thread " for stage " local.stage
    	
    	// resolve
    	if(local.noresolve == NIL)
    	{
    		for(local.i = 1; local.i <= $player.size; local.i++)
    		{
    			local.player = $player[local.i]
    			if(local.player.stage != NIL)
    			{
    				parm.player = local.player
    				if(local.player.stage >= local.stage)
    				{
    					if(level.main_player_handler_debug == 1)
    						println "INFO[jv_mp_players::add_stage_thread]: Resolving thread " local.thread " (stage " local.stage ") for player ["	local.i "]."
    					local.player testthread local.script local.thread
    				}
    			}
    		}
    	}
    
    	if(level.main_player_handler_debug == 1)
    		waitthread debug_threads
    end
    
    /**
    Removes the specified thread from the given stage.
    
    array scriptthread:	script::thread array.
    string stage:		stage to remove thread from.
    */
    clear_stage_thread local.scriptthread local.stage:
    	local.stage = waitthread resolve_stage local.stage
    
    	local.script = local.scriptthread[1]
    	if(local.script == NIL || local.script == NULL)
    	{
    		if(level.script != NIL)
    		{
    			println "WARNING[jv_mp_players::clear_stage_thread]: Invalid script: " local.script " for stage " local.stage ", trying level.script (" level.script ")."
    			local.script = level.script
    		}
    		else
    		{
    			println "ERROR[jv_mp_players::clear_stage_thread]: Invalid script: " local.script " for stage " local.stage "."
    			end
    		}
    	}
    	
    	local.thread = local.scriptthread[2]
    	if(local.thread == NIL || local.thread == NULL)
    	{
    		println "ERROR[jv_mp_players::clear_stage_thread]: Invalid thread: " local.thread " for stage " local.stage
    		end
    	}
    	
    	local.ok = 0
    	for(local.num = 1; local.num <= level.stagethread[local.stage].size; local.num++)
    	{
    		if(level.stagethread[local.stage][local.num] == local.thread)
    		{
    			if(level.stagethreadscript[local.stage][local.num] == local.script)
    			{
    				level.stagethread[local.stage][local.num] = 0
    				println "INFO[jv_mp_players::clear_stage_thread]: Successfully cleared thread " local.script "::" local.thread " for stage " local.stage
    				local.ok = 1
    				break
    			}
    		}
    	}
    	
    	if(local.ok == 0)
    		println "ERROR[jv_mp_players::clear_stage_thread]: Could not remove thread " local.script "::" local.thread " for stage " local.stage
    
    	if(level.main_player_handler_debug == 1)
    		waitthread debug_threads
    end
    
    /**
    Removes all threads from this stage.
    
    string stage: stage to remove threads from.
    */
    clear_stage local.stage:
    	local.stage = waitthread resolve_stage local.stage
    
    	local.i = 0
    	for(local.num = 1; local.num <= level.stagethread[local.stage].size; local.num++)
    	{
    		level.stagethread[local.stage][local.num] = 0
    		local.i++
    	}
    	if(local.i > 0)
    		println "INFO[jv_mp_players::clear_stage]: Successfully cleared " local.i " threads at stage " local.stage
    	else
    		println "WARNING[jv_mp_players::clear_stage]: No threads found at stage " local.stage
    
    	if(level.main_player_handler_debug == 1)
    		waitthread debug_threads
    end
    
    /**
    Outputs all stage threads to console.
    */
    debug_threads:
    	println " "
    	println "INFO: New stage thread array:"
    	println "======================="
    	for(local.st = 1; local.st <= 4; local.st++)
    	{
    		for(local.i = 1; local.i <= level.stagethread[local.st].size; local.i++)
    		{
    			if(level.stagethread[local.st][local.i] == 0)
    				println "[stage " local.st "]: (removed thread)"
    			else
    			println "[stage " local.st "]: " level.stagethreadscript[local.st][local.i] "::" level.stagethread[local.st][local.i]
    		}
    	}
    	println "======================="
    	println " "
    end
    
    /**
    Waits for the player to trigger 
    a $playerspawntrigger entity.
    Internal use.
    */
    player_join_game:
    	local.trigger = spawn trigger_multiple
    	local.trigger setsize ( -16 -16 -16) (16 16 16)
    	local.trigger glue self
    	while(1)
    	{
    		local.trigger waittill trigger
    		if(parm.other == self)
    			break
    		waitframe
    	}
    	local.trigger remove
    end
    
    //=========================//
    // External Search Threads //
    //=========================//
    
    /**
    Returns the entities of the given array with 
    the given targetname.
    */
    get_named_entities local.array local.targetname:
    	local.id = 1
    	for(local.num = 1; local.num <= local.array.size; local.num++)
    	{
    		local.ent = local.array[local.num]
    		if(local.ent)
    		{
    			if(local.ent.targetname == local.targetname)
    			{
    				local.new_array[local.id] = local.ent
    				local.id++
    			}
    		}
    	}
    	if(local.new_array == NIL)
    	{
    		local.new_array = makeArray
    		endArray
    	}
    end local.new_array
    
    /**
    Returns the entities from the array with the
    specified '$tag' key.
    */
    get_tagged_entities local.array local.tagname:
    	local.id = 1
    	for(local.num = 1; local.num <= local.array.size; local.num++)
    	{
    		local.ent = local.array[local.num]
    		if(local.ent)
    		{
    			if(local.ent.tag == local.tagname)
    			{
    				local.new_array[local.id] = local.ent
    				local.id++
    			}
    		}
    	}
    	if(local.new_array == NIL)
    	{
    		local.new_array = makeArray
    		endArray
    	}
    end local.new_array
    
    /**
    Returns the entities from the array within 
    radius distance from the origin vector.
    */
    get_area_entities local.array local.origin local.radius:
    	local.id = 1
    	for(local.num = 1; local.num <= local.array.size; local.num++)
    	{
    		local.ent = local.array[local.num]
    		if(local.ent)
    		{
    			if(vector_within local.ent.origin local.origin local.radius)
    			{
    				local.new_array[local.id] = local.ent
    				local.id++
    			}
    		}
    	}
    	if(local.new_array == NIL)
    	{
    		local.new_array = makeArray
    		endArray
    	}
    end local.new_array
    
    /**
    Returns the entities from the array touching
    the toucher entity.
    */
    get_touching_entities local.array local.toucher:
    	local.id = 1
    	for(local.num = 1; local.num <= local.array.size; local.num++)
    	{
    		local.ent = local.array[local.num]
    		if(local.ent)
    		{
    			if(local.ent isTouching local.toucher)
    			{
    				local.new_array[local.id] = local.ent
    				local.id++
    			}
    		}
    	}
    	if(local.new_array == NIL)
    	{
    		local.new_array = makeArray
    		endArray
    	}
    end local.new_array
    
    /**
    Returns the entities from the array with 
    the specified dmteam.
    */
    get_team_players local.array local.team:
    	local.id = 1
    	for(local.num = 1; local.num <= local.array.size; local.num++)
    	{
    		local.player = local.array[local.num]
    		if(local.player)
    		{
    			if(local.player.dmteam == local.team)
    			{
    				local.new_array[local.id] = local.player
    				local.id++
    			}
    		}
    	}
    	if(local.new_array == NIL)
    	{
    		local.new_array = makeArray
    		endArray
    	}
    end local.new_array
    
    /**
    Returns all players that are currently in the game.
    Doesn't return spectators.
    */
    get_active_players local.array:
    	local.id = 1
    	for(local.num = 1; local.num <= local.array.size; local.num++)
    	{
    		local.player = local.array[local.num]
    		if(local.player)
    		{
    			if(local.player.ingame == 1)
    			{
    				local.new_array[local.id] = local.player
    				local.id++
    			}
    		}
    	}
    	if(local.new_array == NIL)
    	{
    		local.new_array = makeArray
    		endArray
    	}
    end local.new_array
    
    
    //------------------ Bot Scoreboard ---------------------
    setup_kill:
    
    	if(self.detect != NIL && self.detect != NULL)
    	{
    		self.detect remove
    	}
    
    	// Added 8 to the spawnflags 128 so that actors can also trigger it
    	self.detect = spawn trigger_multipleall "spawnflags" "136" 
    	self.detect.origin = self.origin
    	self.detect.angle = self.angle
    	self.detect setthread killed
    	self.detect glue self
    	self.detect.player = self
    	self.detect.team = self.dmteam
    	self.detect.alive = 1
    	self.detect.attacker = NIL	
    	self.detect setsize ( -17 -17 0 ) ( 17 17 92 )
    
    end
    
    killed:
    
    	local.murderer = parm.other
    
    	//check if player is still on the server or on the same team
    	if (self.player == NIL || self.player == NULL || self.team != self.player.dmteam || self.alive == 0 || self.player.dmteam == "spectator")
    	{
    		end
    	}
    
    	//MAIN KILL-HANDLER
    	if ( isAlive self.player != 1 && self.alive == 1 )
    	{	
    		self nottriggerable
    		self.alive = 0
    		self.attacker = local.murderer
    		waitframe
    		
    		//benzin barrel
    		if (local.murderer == NULL) 
    		{
    			if (self.player.deathcount == NIL)
    				self.player.deathcount = 0
    			
    			self.player.deathcount++
    			end
    		}
    		//committed suicide or teamkill
    		if (local.murderer.classname == "Player")
    		{
    			if ( local.murderer == self.player || local.murderer.dmteam == self.player.dmteam )
    			{
    				if ( local.murderer.killcount == NIL )
    				{
    					local.murderer.killcount = 0
    					local.murderer.killcount--
    				}
    				else if ( local.murderer.killcount != NIL )
    				{
    					local.murderer.killcount--
    				}
    			}
    			//no traitor
    			else if ( local.murderer.dmteam != self.player.dmteam )
    			{
    				if ( local.murderer.killcount == NIL )
    				{
    					local.murderer.killcount = 0
    					local.murderer.killcount++
    				}
    				else if ( local.murderer.killcount != NIL )
    				{
    					local.murderer.killcount++
    				}
    			}
    		}
    		else if ( local.murderer.classname == "Actor" && level.sc_running == 1)
    		{
    			for (local.u = 1; local.u <= level.botspawn.size; local.u++)
    			{
    				if(local.murderer == level.botspawn[local.u] && local.murderer.dmteam == self.player.dmteam)
    				{
    					local.numm = level.botspawn[local.u].num
    					level.sc_kills[local.numm]--
    
    					if ($player.size == 1)
    						thread global/jv_bots/killboard.scr::show (level.botname[local.numm] + " has teamkilled " + (getcvar "name"))
    					else
    						thread global/jv_bots/killboard.scr::show (level.botname[local.numm] + " has teamkilled Player " + self.player.entnum)
    
    					self.player iprint ("You got killed by " + level.botname[local.numm])
    				}
    				else if(local.murderer == level.botspawn[local.u] && local.murderer.dmteam != self.player.dmteam)
    				{
    					local.numm = level.botspawn[local.u].num
    					level.sc_kills[local.numm]++
    
    					if ($player.size == 1)
    						thread global/jv_bots/killboard.scr::show (level.botname[local.numm] + " has killed " + (getcvar "name"))
    					else
    						thread global/jv_bots/killboard.scr::show (level.botname[local.numm] + " has killed Player " + self.player.entnum)
    
    					self.player iprint ("You got killed by " + level.botname[local.numm]) 1
    				}
    			}
    		}
    	
    		if (self.player.deathcount == NIL)
    			self.player.deathcount = 0
    
    		self.player.deathcount++
    		self immediateremove
    	}
    
    end
    //----------------------------------------------------------
    Attached Files Attached Files

  2. #2

    Default

    Does that happen for any player who joins the server, or just client 0 (probably the first person to join the server)?

  3. #3

    Default

    Hey mate, Thanks for reply.

    Just client 0. Client 0 is always blank on Sor's bot scoreboard...until a 2nd player joins or i set the the player name on the server.

    As soon as a 2nd human (Client 1) enters the match - the autonaming kicks in and we see:

    Client 0 (me) - becomes "Player 0" and the new player - Client 1 - becomes "Player 1" (this is correct functioning of the bot scoreboard).

    So yeah, it's just nailing what is going on with client 0 when they are playing by themselves with the bots. It needs to recognise the true player's name.
    (note: this is not on LAN. My off-site server).

    Hmmm.

    Any help is always appreciated.

    Gaz.

  4. #4

    Default

    This isn't a "fix" for your issue, I'm just curious if the same issues will happen when you do it --

    If it's an issue with client 0 specifically, and not just the first player to enter the game you could try to set one private slot in your server.cfg then join the server without using the join password (that slot should remain empty ie. typing "rcon status" should show your client ID as 1).

    seta sv_privateClients 1
    set sv_privatepassword "password"

    If that works, it will make it less awkward for the server until someone can figure out what the real issue is. I'm still poking through the PK3, but so far nothing sticks out.

  5. #5

    Default

    Interesting idea. And thank you. When I did that, my player of course became "client ID 1" when I joined.
    But, Sor's scoreboard still showed the player name entry as "blank" on the scoreboard, regardless. Hmmm....

  6. #6

    Default

    Alright, so it wants two people in the server before it will kick in and run the script the right way. I still haven't seen anything out of the ordinary. I'll keep digging. Where did you download that scoreboard mod from? It could be that the file you've got is corrupted? Might try grabbing it from AAAA and throwing it on your server to see if anything is different. (Just running through the troubleshooting steps here lol)

  7. #7

    Default

    Good idea, thanks again. But alas, its still blank on the first human player name. And again, as soon as I type "rcon set name Oh_Gaz", it updates to that name.

    Strange indeed...

  8. #8
    Purple Developer Purple Elephant1au's Avatar
    Join Date
    Feb 2012
    Location
    Australia
    Posts
    1,259

    Default

    Hi

    The reason it gets the rcon name is because thats how its set up, if $player.size == 1 , then it gets the cvar name from the server, else it prints the players entnum.

    Its in the global/jv_bots/botscoreboard.scr

    Line 117 to 120

    Code:
    if ($player.size == 1)
    level.botsc_array[local.c][1] = getcvar (name)
    else
    level.botsc_array[local.c][1] = ("Player " + $player[local.i].entnum)
    So if you want it to either always use player number, just remove the if statement and else and just run
    level.botsc_array[local.c][1] = ("Player " + $player[local.i].entnum)

    Or ONCE you install reborn you can actually get the players name and use the following line
    level.botsc_array[local.c][1] = netname $player[local.i]

    NB if you go with reborn and get players actual name, you might have to limit the size of the name to a certain amount of characters, or it might stuff up the hud.

    EDIT: Oh and @Oh_Gaz, i have tried to get a copy of the bots running locally, but it keeps causing mohaa server to crash lol doesnt like spawning script_objects. I will keep trying, no idea why it hates me
    Last edited by Purple Elephant1au; April 13th, 2015 at 03:12 AM.

    Purple's Playground
    OBJ :
    103.29.85.127:12203
    xfire: purpleelephant1au
    email: purpleelephant1au@gmail.com
    skydrive: PurpleElephantSkydrive




  9. #9

    Default

    Thanks Purple! Incredible how guys can read the code just like a second language.

    One thing: I can now see "Player 0" all ok in the menu. Great start. But can I have it display "Oh_Gaz" which is the player name in my configs, just when there is only one player? I presume that the old entry was meant to do this...but not sure why it didnt work...
    Last edited by OhGaz; April 13th, 2015 at 08:06 AM.

  10. #10
    Developer Sor's Avatar
    Join Date
    Aug 2010
    Location
    The Medieval City of Bruges
    Posts
    747

    Default

    Not without installing the unofficial patch. The reason the code is written that way is because it was never meant to be used in server-side games.
    A client hosting the LAN game would have the cvar set to the name used in multiplayer. Other clients joining over the local network would be listed
    by their client number because (1) there was no way to obtain their names in script at the time and (2) it makes administration easier for the host.

    EDIT: Also, try this version of jv_mp_players.scr instead. I've removed some stuff you don't need. You'll have a lot less errors in your console as well.
    /**Main Player Handler script for MoH:AA (t)dm/obj
    ===============================================
    by jv_map
    version 1.1
    ---------------------------------------------
    Copyright (c) 2002-2003 Jeroen Vrijkorte
    All rights reserved.
    ---------------------------------------------
    Distribution is allowed provided all subsequent
    conditions are met:
    
    
    1. Commercial use is prohibited.
    
    
    2. The above copyright notice and this permission notice shall
    be included in all copies or substantial portions of the file.
    
    
    3. If you have made modifications to the original files you must
    cause the modified files to carry prominent notices stating
    that you changed the files.
    
    
    COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT,
    SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE
    SOFTWARE OR DOCUMENTATION.
    ---------------------------------------------
    jv_map@planetmedalofhonor.com
    http://www.planetmedal.com/freebrief
    ---------------------------------------------
    */
    
    
    /**
    ---------------------------------------------
    Main Player Handler
    
    
    Runs threads when a player joins the game.
    ---------------------------------------------
    */
    
    
    /**
    Main thread. Run at startup below waittill spawn.
    
    
    Use level.main_player_handler_debug = 1 for verbose output.
    */
    main_player_handler:
        if(level.main_player_handler == NIL)
            level.main_player_handler = 0
    
    
        level.main_player_handler++
    
        if(level.main_player_handler > 1)
        {
            println "INFO[jv_mp_players::main_player_handler]: Handler already running, exiting."
            end
        }
    
        waitthread reset
    
    
        if(level.main_player_handler_firstplayerfix == 1)
            $player[1] thread firstplayerbugfix
    
        while(level.main_player_handler >= 1)
        {
            for(local.playernum = 1; local.playernum <= $player.size; local.playernum++)
            {
                local.player = $player[local.playernum]
                level.player = local.player
                if(local.player.checked != 1)
                {
                    local.player.checked = 1
                    local.player thread child_player_handler local.playernum
                }
            }
            wait 0.5
        }
        println "INFO[jv_mp_players::main_player_handler]: Main player handler terminated."
    end
    
    
    /**
    Removes possibly fake player from the map. Optional.
    
    
    Set level.main_player_handler_firstplayerfix = 1
    to fix the first player bug on dedicated servers.
    */
    firstplayerbugfix:
        if(self.dmteam == spectator)
        {
            println "INFO[jv_mp_players::firstplayerbugfix]: Verifying first player..."
            local.location = self.origin
            local.angles = self.angles
            wait 5
            if(self != NULL && self.dmteam == spectator && self.ingame != 1 && local.location == self.origin && local.angles == self.angles)
            {
                println "INFO[jv_mp_players::firstplayerbugfix]: Warning first player..."
                local.times = 1
                while(self != NULL && self.dmteam == spectator && self.ingame != 1 && local.times <= 10 && self.useheld == 0 && local.location == self.origin && local.angles == self.angles)
                {
                    self iprint "Please move or hold USE"
                    wait 1
                    local.times++
                }
                // waited ten
                if(self != NULL && local.times >= 10)
                {
                    // disconnect and remove ent
                    self iprint "Disconnected, sorry"
                    println "INFO[jv_mp_players::firstplayerbugfix]: Kicked first player"
                    waitframe
                    if(self)
                        self remove
                }
                else
                {
                    self iprint "Ok thanks"
                    println "INFO[jv_mp_players::firstplayerbugfix]: First player is ok"
                }
            }
            else
                println "INFO[jv_mp_players::firstplayerbugfix]: First player is ok"
        }
    end
    
    
    /**
    Shutdown one main player handler request.
    */
    shutdown:
        level.main_player_handler--
    end
    
    
    /**
    Shutdown main player handler regardless
    of the number of requests.
    */
    kill:
        level.main_player_handler = -1
    end
    
    
    /**
    Resets all players to 'not checked'. Internal use.
    */
    reset:
        for(local.playernum = 1; local.playernum <= $player.size; local.playernum++)
        {
            local.player = $player[local.playernum]
            local.player.checked = 0
        }
    end
    
    
    /**
    Player specific thread. Internal use.
    */
    child_player_handler local.debugnum:
        local.entnum = self.entnum
        if(level.main_player_handler_debug)
            println "INFO[jv_mp_players::child_player_handler]: Child handler started for player " local.debugnum " (entnum: " local.entnum ")."
        while(level.main_player_handler >= 1 && self != NULL)
        {
            self.ingame = 0
            self thread player_stage_thread 1
            self.stage = 1
            //--- stage 1 ---//
            if(level.main_player_handler_debug)
                println "INFO[jv_mp_players::child_player_handler]: Player " local.debugnum " has entered stage 1."
    
            while (level.main_player_handler >= 1 && self != NULL && (self.dmteam == "spectator" || !(isAlive self)))
                wait 0.5
    
            if(level.main_player_handler >= 1 && self != NULL && isAlive self)
            {
                local.team = self.dmteam
                //--- stage 2 ---//
                if(level.main_player_handler_debug)
                    println "INFO[jv_mp_players::child_player_handler]: Player " local.debugnum " has entered stage 2."
                self thread player_stage_thread 2
                self.stage = 2
                self waitthread player_join_game
                //--- stage 3 ---//
                self thread player_stage_thread 3
                if(level.main_player_handler_debug)
                    println "INFO[jv_mp_players::child_player_handler]: Player " local.debugnum " has entered stage 3."
                self.stage = 3
                self.ingame = 1
    
    
    // ---- Bot Scoreboard ----
                while(level.main_player_handler >= 1 && self != NULL && isAlive self && local.team == self.dmteam)
                {
                    if (self.detect == NIL || self.detect == NULL)
                        self thread setup_kill
    
    
                    wait 0.1
                }
    // ------------------------
            }
            if(self != NULL && level.main_player_handler >= 1)
            {
                //--- stage 4 ---//
                self thread player_stage_thread 4
                if(level.main_player_handler_debug)
                    println "INFO[jv_mp_players::child_player_handler]: Player " local.debugnum " has entered stage 4."
                self.stage = 4
            }
        }
        if(level.main_player_handler_debug)
            println "INFO[jv_mp_players::child_player_handler]: Child handler terminated for player " local.debugnum
    end
    
    
    /**
    Run all threads for the given player from the specified stage.
    
    
    integer stage: number of stage to run threads of.
    */
    player_stage_thread local.stage:
        for(local.numthread = 1; local.numthread <= level.stagethread[local.stage].size; local.numthread++)
        {
            local.thread = level.stagethread[local.stage][local.numthread]
            local.script = level.stagethreadscript[local.stage][local.numthread]
            if(local.thread != NIL && local.thread != 0)
            {
                if(level.main_player_handler_debug == 1)
                    println "INFO[jv_mp_players::player_stage_thread]: Running thread " local.thread " (stage " local.stage ")"
                parm.player = self
                self testthread local.script local.thread
            }
            else if(local.thread != 0)
                println "WARNING[jv_mp_players::player_stage_thread]: Invalid thread definition [thread: " local.thread ", script: " local.script "] (stage " local.stage ")"
        }
    end
    
    
    /**
    Resolves string stages to stage numbers. Internal use.
    
    
    string stage: stage to resolve
    */
    resolve_stage local.stage:
        local.prestage = local.stage
    
        switch(local.stage)
        {
            start:
                local.stage = 1
                break
            prepare:
                local.stage = 2
                break
            join:
                local.stage = 3
                break
            death:
                local.stage = 4
        }
    
        if(level.main_player_handler_debug == 1 && local.prestage != local.stage)
            println "INFO[jv_mp_players::resolve_stage]: Resolved stage " local.prestage " to stage " local.stage
    end local.stage
    
    
    /**
    Adds a stage thread for all players. This thread will be run
    when a player enters the specified stage. Stages are:
        start (1):         player enters the game
        prepare (2):    player joins a team
        join (3):        player enters the game
        death(4):        player dies -> goes to stage 3 again if respawn is enabled.
    
    
    Arguments are as follows:
    
    
    array scriptthread:    array defined as:
        [1]: string script file.
        [2]: string thread.
    string stage:        stage that should trigger this thread.
    boolean noresolve:    set to '1' to prevent stage resolving. Not recommended.
    */
    add_stage_thread local.scriptthread local.stage local.noresolve:
        // usage example: waitthread global/jv_mp_players::add_stage_thread "maps/dm/mymap.scr"::start prepare
    
        local.stage = waitthread resolve_stage local.stage
    
    
        local.thread = local.scriptthread[2]
        if(local.thread == NIL || local.thread == NULL)
        {
            println "ERROR[jv_mp_players::add_stage_thread]: Invalid thread: " local.thread " for stage " local.stage
            end
        }
    
        local.script = local.scriptthread[1]
        if(local.script == NIL || local.script == NULL)
        {
            if(level.script != NIL)
            {
                println "WARNING[jv_mp_players::add_stage_thread]: Invalid script: " local.script " for stage " local.stage ", setting to level.script (" level.script ")."
                local.script = level.script
            }
            else
            {
                println "ERROR[jv_mp_players::add_stage_thread]: Invalid script: " local.script " for stage " local.stage "."
                end
            }
        }
    
        local.siz = level.stagethread[local.stage].size
    
        if(local.siz < 0)
            local.siz = 0
    
        level.stagethread[local.stage][local.siz + 1] = local.thread
        level.stagethreadscript[local.stage][local.siz + 1] = local.script
    
        println "INFO[jv_mp_players::add_stage_thread]: Added stage thread " local.script "::" local.thread " for stage " local.stage
    
        // resolve
        if(local.noresolve == NIL)
        {
            for(local.i = 1; local.i <= $player.size; local.i++)
            {
                local.player = $player[local.i]
                if(local.player.stage != NIL)
                {
                    parm.player = local.player
                    if(local.player.stage >= local.stage)
                    {
                        if(level.main_player_handler_debug == 1)
                            println "INFO[jv_mp_players::add_stage_thread]: Resolving thread " local.thread " (stage " local.stage ") for player ["    local.i "]."
                        local.player testthread local.script local.thread
                    }
                }
            }
        }
    
    
        if(level.main_player_handler_debug == 1)
            waitthread debug_threads
    end
    
    
    /**
    Removes the specified thread from the given stage.
    
    
    array scriptthread:    script::thread array.
    string stage:        stage to remove thread from.
    */
    clear_stage_thread local.scriptthread local.stage:
        local.stage = waitthread resolve_stage local.stage
    
    
        local.script = local.scriptthread[1]
        if(local.script == NIL || local.script == NULL)
        {
            if(level.script != NIL)
            {
                println "WARNING[jv_mp_players::clear_stage_thread]: Invalid script: " local.script " for stage " local.stage ", trying level.script (" level.script ")."
                local.script = level.script
            }
            else
            {
                println "ERROR[jv_mp_players::clear_stage_thread]: Invalid script: " local.script " for stage " local.stage "."
                end
            }
        }
    
        local.thread = local.scriptthread[2]
        if(local.thread == NIL || local.thread == NULL)
        {
            println "ERROR[jv_mp_players::clear_stage_thread]: Invalid thread: " local.thread " for stage " local.stage
            end
        }
    
        local.ok = 0
        for(local.num = 1; local.num <= level.stagethread[local.stage].size; local.num++)
        {
            if(level.stagethread[local.stage][local.num] == local.thread)
            {
                if(level.stagethreadscript[local.stage][local.num] == local.script)
                {
                    level.stagethread[local.stage][local.num] = 0
                    println "INFO[jv_mp_players::clear_stage_thread]: Successfully cleared thread " local.script "::" local.thread " for stage " local.stage
                    local.ok = 1
                    break
                }
            }
        }
    
        if(local.ok == 0)
            println "ERROR[jv_mp_players::clear_stage_thread]: Could not remove thread " local.script "::" local.thread " for stage " local.stage
    
    
        if(level.main_player_handler_debug == 1)
            waitthread debug_threads
    end
    
    
    /**
    Removes all threads from this stage.
    
    
    string stage: stage to remove threads from.
    */
    clear_stage local.stage:
        local.stage = waitthread resolve_stage local.stage
    
    
        local.i = 0
        for(local.num = 1; local.num <= level.stagethread[local.stage].size; local.num++)
        {
            level.stagethread[local.stage][local.num] = 0
            local.i++
        }
        if(local.i > 0)
            println "INFO[jv_mp_players::clear_stage]: Successfully cleared " local.i " threads at stage " local.stage
        else
            println "WARNING[jv_mp_players::clear_stage]: No threads found at stage " local.stage
    
    
        if(level.main_player_handler_debug == 1)
            waitthread debug_threads
    end
    
    
    /**
    Outputs all stage threads to console.
    */
    debug_threads:
        println " "
        println "INFO: New stage thread array:"
        println "======================="
        for(local.st = 1; local.st <= 4; local.st++)
        {
            for(local.i = 1; local.i <= level.stagethread[local.st].size; local.i++)
            {
                if(level.stagethread[local.st][local.i] == 0)
                    println "[stage " local.st "]: (removed thread)"
                else
                println "[stage " local.st "]: " level.stagethreadscript[local.st][local.i] "::" level.stagethread[local.st][local.i]
            }
        }
        println "======================="
        println " "
    end
    
    
    /**
    Waits for the player to trigger
    a $playerspawntrigger entity.
    Internal use.
    */
    player_join_game:
        local.trigger = spawn trigger_multiple
        local.trigger setsize ( -16 -16 -16) (16 16 16)
        local.trigger glue self
        while(1)
        {
            local.trigger waittill trigger
            if(parm.other == self)
                break
            waitframe
        }
        local.trigger remove
    end
    
    
    //=========================//
    // External Search Threads //
    //=========================//
    
    
    /**
    Returns the entities of the given array with
    the given targetname.
    */
    get_named_entities local.array local.targetname:
        local.id = 1
        for(local.num = 1; local.num <= local.array.size; local.num++)
        {
            local.ent = local.array[local.num]
            if(local.ent)
            {
                if(local.ent.targetname == local.targetname)
                {
                    local.new_array[local.id] = local.ent
                    local.id++
                }
            }
        }
        if(local.new_array == NIL)
        {
            local.new_array = makeArray
            endArray
        }
    end local.new_array
    
    
    /**
    Returns the entities from the array with the
    specified '$tag' key.
    */
    get_tagged_entities local.array local.tagname:
        local.id = 1
        for(local.num = 1; local.num <= local.array.size; local.num++)
        {
            local.ent = local.array[local.num]
            if(local.ent)
            {
                if(local.ent.tag == local.tagname)
                {
                    local.new_array[local.id] = local.ent
                    local.id++
                }
            }
        }
        if(local.new_array == NIL)
        {
            local.new_array = makeArray
            endArray
        }
    end local.new_array
    
    
    /**
    Returns the entities from the array within
    radius distance from the origin vector.
    */
    get_area_entities local.array local.origin local.radius:
        local.id = 1
        for(local.num = 1; local.num <= local.array.size; local.num++)
        {
            local.ent = local.array[local.num]
            if(local.ent)
            {
                if(vector_within local.ent.origin local.origin local.radius)
                {
                    local.new_array[local.id] = local.ent
                    local.id++
                }
            }
        }
        if(local.new_array == NIL)
        {
            local.new_array = makeArray
            endArray
        }
    end local.new_array
    
    
    /**
    Returns the entities from the array touching
    the toucher entity.
    */
    get_touching_entities local.array local.toucher:
        local.id = 1
        for(local.num = 1; local.num <= local.array.size; local.num++)
        {
            local.ent = local.array[local.num]
            if(local.ent)
            {
                if(local.ent isTouching local.toucher)
                {
                    local.new_array[local.id] = local.ent
                    local.id++
                }
            }
        }
        if(local.new_array == NIL)
        {
            local.new_array = makeArray
            endArray
        }
    end local.new_array
    
    
    /**
    Returns the entities from the array with
    the specified dmteam.
    */
    get_team_players local.array local.team:
        local.id = 1
        for(local.num = 1; local.num <= local.array.size; local.num++)
        {
            local.player = local.array[local.num]
            if(local.player)
            {
                if(local.player.dmteam == local.team)
                {
                    local.new_array[local.id] = local.player
                    local.id++
                }
            }
        }
        if(local.new_array == NIL)
        {
            local.new_array = makeArray
            endArray
        }
    end local.new_array
    
    
    /**
    Returns all players that are currently in the game.
    Doesn't return spectators.
    */
    get_active_players local.array:
        local.id = 1
        for(local.num = 1; local.num <= local.array.size; local.num++)
        {
            local.player = local.array[local.num]
            if(local.player)
            {
                if(local.player.ingame == 1)
                {
                    local.new_array[local.id] = local.player
                    local.id++
                }
            }
        }
        if(local.new_array == NIL)
        {
            local.new_array = makeArray
            endArray
        }
    end local.new_array
    
    
    
    
    //------------------ Bot Scoreboard ---------------------
    setup_kill:
    
    
        if(self.detect != NIL && self.detect != NULL)
        {
            self.detect remove
        }
    
    
        // Added 8 to the spawnflags 128 so that actors can also trigger it
        self.detect = spawn trigger_multipleall "spawnflags" "136"
        self.detect.origin = self.origin
        self.detect.angle = self.angle
        self.detect setthread killed
        self.detect glue self
        self.detect.player = self
        self.detect.team = self.dmteam
        self.detect.alive = 1
        self.detect.attacker = NIL
        self.detect setsize ( -17 -17 0 ) ( 17 17 92 )
    
    
    end
    
    
    killed:
    
    
        local.murderer = parm.other
    
    
        //check if player is still on the server or on the same team
        if (self.player == NIL || self.player == NULL || self.team != self.player.dmteam || self.alive == 0 || self.player.dmteam == "spectator")
        {
            end
        }
    
    
        //MAIN KILL-HANDLER
        if ( isAlive self.player != 1 && self.alive == 1 )
        {
            self nottriggerable
            self.alive = 0
            self.attacker = local.murderer
            waitframe
    
            //benzin barrel
            if (local.murderer == NULL)
            {
                if (self.player.deathcount == NIL)
                    self.player.deathcount = 0
    
                self.player.deathcount++
                end
            }
            //committed suicide or teamkill
            if (local.murderer.classname == "Player")
            {
                if ( local.murderer == self.player || local.murderer.dmteam == self.player.dmteam )
                {
                    if ( local.murderer.killcount == NIL )
                    {
                        local.murderer.killcount = 0
                        local.murderer.killcount--
                    }
                    else if ( local.murderer.killcount != NIL )
                    {
                        local.murderer.killcount--
                    }
                }
                //no traitor
                else if ( local.murderer.dmteam != self.player.dmteam )
                {
                    if ( local.murderer.killcount == NIL )
                    {
                        local.murderer.killcount = 0
                        local.murderer.killcount++
                    }
                    else if ( local.murderer.killcount != NIL )
                    {
                        local.murderer.killcount++
                    }
                }
            }
            else if ( local.murderer.classname == "Actor" && level.sc_running == 1)
            {
                for (local.u = 1; local.u <= level.botspawn.size; local.u++)
                {
                    if(local.murderer == level.botspawn[local.u] && local.murderer.dmteam == self.player.dmteam)
                    {
                        local.numm = level.botspawn[local.u].num
                        level.sc_kills[local.numm]--
                        self.player iprint ("You got killed by " + level.botname[local.numm])
                    }
                    else if(local.murderer == level.botspawn[local.u] && local.murderer.dmteam != self.player.dmteam)
                    {
                        local.numm = level.botspawn[local.u].num
                        level.sc_kills[local.numm]++
                        self.player iprint ("You got killed by " + level.botname[local.numm]) 1
                    }
                }
            }
    
            if (self.player.deathcount == NIL)
                self.player.deathcount = 0
    
    
            self.player.deathcount++
            self immediateremove
        }
    
    
    end
    //----------------------------------------------------------


    I've done the same clean-up for spawnhandler_default.scr
    /**Multiplayer Bot script for MoH:AA obj
    =============================================
    by jv_map
    version 1.1
    ---------------------------------------------
    Copyright (c) 2002-2003 Jeroen Vrijkorte
    All rights reserved.
    ---------------------------------------------
    Distribution is allowed provided all subsequent
    conditions are met:
    
    
    1. Commercial use is prohibited.
    
    
    2. The above copyright notice and this permission notice shall
    be included in all copies or substantial portions of the file.
    
    
    3. If you have made modifications to the original files you must
    cause the modified files to carry prominent notices stating
    that you changed the files.
    
    
    COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT,
    SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE
    SOFTWARE OR DOCUMENTATION.
    ---------------------------------------------
    jv_map@planetmedalofhonor.com
    http://www.planetmedal.com/freebrief
    ---------------------------------------------
    */
    
    
    /**
    ---------------------------------------------
    Main Spawn Handler Script
    
    
    Controls the (re)spawning of bots.
    Executes kill events, such as spawning of
    medkits, kill notifications to players and
    sporadically sends a taunt command to attacker.
    ---------------------------------------------
    */
    
    
    /**
    ---------------------------------------------
    Modifications by Blade
    Added/updated Botscoreboard vars & counters
    ---------------------------------------------
    */
    
    
    /**
    Initialize counter variables. Internal use.
    */
    setup:
    	level.botlastid = 0
    	level.bots = 0
    	level.nodrophealth = 1
    	level.botnum = 0
    
    
    	level.teambots[allies] = 0
    	level.teambots[axis] = 0
    	level.jvbot_respawning = waitthread level.jvbot_main_script::getrankedvar 1 level.jvbot_respawning jvbot_respawning int NIL 1
    end
    
    
    shutdown:
    	// no shutdown
    end
    
    
    /**
    Adds a bot which will automatically respawn.
    Returns the ID of the new bot.
    Can be called externally.
    
    
    string name:	name to use for bot.
    string team:	allies or axis.
    string spawner: sets a spawner identifier to keep track of bots.
    */
    addbot local.name local.team local.spawner:
    	if(level.jvbot_jv_mp_ai_running == 1)
    	{
    		level.botnum++ // unique ID
    		local.num = level.botnum
    		level.num = local.num
    
    
    		if(local.spawner == NIL)
    			local.spawner = "(unknown)"
    
    
    		local.model = waitthread getmodel local.team
    		local.weaponinfo = waitthread level.jvbot_modscript[libweapon]::getweapon local.team local.model local.name
    
    		level.botenabled[local.num] = 1
    		level.botremoved[local.num] = 0
    		level.botname[local.num] = local.name
    		level.botteam[local.num] = local.team
    		level.botmodel[local.num] = local.model
    		level.botspawner[local.num] = local.spawner
    		level.botweaponinfo[local.num] = local.weaponinfo
    
    
    // ---- Bot Scoreboard ----
    		level.sc_kills[local.num] = 0
    		level.sc_deaths[local.num] = 0
    // ------------------------
    
    
    		thread main local.num
    
    
    // ---- Bot Scoreboard ----
    		if (level.sc_running != 1)
    		{
    			println "INFO[spawnhandler_default::init]: Executing the Bot Scoreboard thread"
    			exec global/jv_bots/botscoreboard.scr
    		}
    // ------------------------
    	}
    	else
    		println "ERROR[spawnhandler_default::addbot]: Bot script not running."
    end local.num
    
    
    /**
    Kicks the bot with the given ID.
    
    
    integer num: ID of bot to be kicked.
    */
    kickbot local.num:
    	level.botenabled[local.num] = 0
    	waitthread removebot local.num
    end
    
    
    /**
    Kicks all bots without notification.
    */
    kickall:
    	println "INFO[spawnhandler_default::kickall]: Kicking all bots"
    	if(level.botnum != NIL)
    	{
    		for(local.i = 1; local.i <= level.botnum; local.i++)
    			waitthread kickbot local.i
    	}
    end
    
    
    /**
    Switches a bot to an other team.
    Unsupported.
    */
    switchbot local.num local.team:
    	if(local.team != level.botteam[local.num])
    	{
    		local.model = waitthread getmodel local.team
    		local.weaponinfo = waitthread level.jvbot_modscript[libweapon]::getweapon local.team local.model level.botname[local.num]
    
    		waitthread removebot local.num
    		level.botteam[local.num] = local.team
    		level.botmodel[local.num] = local.model
    		level.botweaponinfo[local.num] = local.weaponinfo
    	}
    end
    
    
    /**
    Immediately removes the bot. Internal use.
    
    
    integer num: ID of bot to remove.
    */
    removebot local.num:
    	level.botremoved[local.num] = 1
    	if(level.botstate[local.num] == prepare)
    	{
    		level.botspawn[local.num].handled = 1
    		while(level.botstate[local.num] == prepare)
    		{
    			waitframe
    			wait level.jvbot_loopdelay
    		}
    	}
    	if(level.botstate[local.num] == active)
    		level.botspawn[local.num] bedead
    end
    
    
    /**
    Main bot handler. Internal use.
    
    
    integer num: ID of bot for botspawn identification.
    */
    main local.num:
    	local.name = level.botname[local.num]
    
    	local.model = level.botmodel[local.num]
    	level.botstate[local.num] = entering
    	while(level.botenabled[local.num] == 1)
    	{
    		local.team = level.botteam[local.num]
    		level.teambots[local.team]++
    		if(local.team == allies)
    			iprintlnbold_noloc local.name " has joined the Allies"
    		else
    			iprintlnbold_noloc local.name " has joined the Axis"
    
    
    
    		while(level.botenabled[local.num] == 1 && level.botteam[local.num] == local.team)
    		{
    			if(level.jvbot_g_allowspawn == 0)
    				println "WARNING[spawnhandler_default::main]: Forced bot spawn after blockjoin for " local.name
    
    			local.spawnposition = waitthread getspawnposition local.team
    			waitthread spawn local.spawnposition local.num
    
    			while(level.jvbot_respawning == 0 && level.botenabled[local.num] == 1 && level.botteam[local.num] == local.team)
    				wait 1
    
    			if(level.botenabled[local.num] == 1)
    				wait ( (randomfloat 3) + 5)
    			level.botremoved[local.num] = 0
    		}
    		waitframe
    		level.teambots[local.team]--
    	}
    	level.botstate[local.num] = away
    	iprintlnbold_noloc local.name " has left the battle"
    end
    
    
    /**
    Spawns a bot and waits for death. Creates a medkit and
    sends a kill event to the attacker. Internal use.
    
    
    entity spawnposition:	location to spawn the bot
    integer num:			bot ID
    */
    spawn local.spawnposition local.num:
    	level.botstate[local.num] = prepare
    	local.team = level.botteam[local.num]
    	local.botname = level.botname[local.num]
    	level.botname1a = local.botname
    	if(level.jvbot_forcemodels == 1)
    	{
    		if(local.team == allies)
    			local.model = level.jvbot_alliespreset[1]
    		else
    			local.model = level.jvbot_axispreset[1]
    	}
    	else
    		local.model = level.botmodel[local.num]
    	local.weaponinfo = level.botweaponinfo[local.num]
    
    	local.health_bonus = 10 * level.jvbot_skill - 20
    
    	local.newbot = spawn local.model origin local.spawnposition.origin
    
    
    	if(level.jvbot_showavatar == 1)
    	{
    		local.newbot.headicon = spawn script_model model ("models/hud/" + local.team + ".tik")
    		local.newbot.headicon attach local.newbot "Bip01 Neck"
    	}
    
    
    	level.botspawn[local.num] = local.newbot
    	local.newbot.num = local.num
    	local.newbot hide
    	local.newbot nodamage
    	local.newbot notsolid
    	local.newbot threatbias ignoreme
    	local.newbot ai_off
    	local.newbot.health = 100 + local.health_bonus
    
    	if(local.spawnposition.yaw == NIL || local.spawnposition.yaw == NULL)
    		local.spawnposition.yaw = 0
    
    	local.newbot.angles = ( 0 local.spawnposition.yaw 0 )
    	local.newbot.dmteam = local.team
    
    
    	local.newbot waitthread level.jvbot_modscript[libweapon]::setweapon local.weaponinfo
    	local.newbot waitthread setgeneral
    	local.newbot.base_accuracy = local.newbot.accuracy
    
    	local.newbot forceActivate
    
    	level.bots++
    	local.id = waitthread getindex
    	if(local.id > level.botlastid)
    		level.botlastid = local.id
    	level.actualbots[local.id] = local.newbot
    	local.newbot.targetname = "ai: " + local.id
    	local.name = local.newbot.targetname
    	local.newbot.cur_task_priority = 0
    
    	while(isAlive local.newbot && local.newbot.handled != 1)
    	{
    		waitframe
    		wait level.jvbot_loopdelay
    	}
    
    	local.newbot ai_on
    	local.newbot takedamage
    	local.newbot solid
    	local.newbot show
    	local.newbot threatbias 0
    	local.newbot thread level.jvbot_main_script::botcontrol
    	level.botstate[local.num] = active
    	local.newbot thread sneakshot
    
    	local.newbot waittill death
    // ---- Bot Scoreboard ----
    	level.sc_deaths[local.num]++
    // ------------------------
    	waitthread setlastbotid
    	level.botstate[local.num] = dead
    
    	if(local.newbot.headicon)
    		local.newbot.headicon remove
    
    	if(level.botremoved[local.num] != 1)
    	{
    		////////////////Sor's Fixes//////////////////////////
    		waitframe
    		waitframe
    
    
    		local.attacker = local.newbot.fact.attacker
    
    
    		waitframe
    		waitframe
    
    
    		if (local.attacker == NIL || local.attacker == NULL)
    		{
    			println "FIX: Something killed a bot!"
    		}
    		//////////////////////////////////////////////////
    		else if(local.attacker.classname == "Player")
    		{
    			if(local.attacker.dmteam == local.newbot.dmteam)
    			{
    				local.nomedkit = 1
    				local.bold = 0
    // ---- Bot Scoreboard ----
    				local.attacker.bot_killcount--
    // ------------------------
    			}
    			else
    			{
    				local.bold = 1
    // ---- Bot Scoreboard ----
    				local.attacker.bot_killcount++
    // ------------------------
    			}
    
    			if(local.botname != NIL)
    				local.attacker iprint ("You killed " + local.botname) local.bold
    			else
    				local.attacker iprint "You killed a bot" local.bold
    		}
    		else if(local.attacker.classname == "Actor")
    		{
    // ---- Bot Scoreboard ----
    			for (local.u = 1; local.u <= level.botspawn.size; local.u++)
    			{
    				if(local.attacker == level.botspawn[local.u] && local.attacker.dmteam == local.newbot.dmteam)
    				{
    					local.numm = level.botspawn[local.u].num
    					level.sc_kills[local.numm]--
    				}
    				else if(local.attacker == level.botspawn[local.u] && local.attacker.dmteam != local.newbot.dmteam)
    				{
    					local.numm = level.botspawn[local.u].num
    					level.sc_kills[local.numm]++
    				}
    			}
    // ------------------------
    			local.otherbot = local.newbot.fact.attacker
    			local.num = randomint 20
    			if(local.num == 0)
    				local.otherbot thread killhappiness
    		}
    		////////////////Sor's Fixes//////////////////////////
    		else if (local.attacker.classname != "Player" && local.attacker.classname != "Actor")
    		{
    			println "FIX: Something killed a bot!"
    		}
    		/////////////////////////////////////////////////////
    
    
    		if(local.newbot.enemy != NULL)
    		{
    			if(isAlive local.newbot.enemy)
    			{
    				local.luckyguy = local.newbot.enemy
    				if(local.luckyguy.classname == "Actor" && local.luckyguy.health < 50 && local.luckyguy != local.attacker)
    					local.luckyguy thread saythanks local.attacker
    			}
    		}
    		if(local.nomedkit != 1)
    		{
    			local.medkit = spawn models/items/dm_50_healthbox.tik origin local.newbot.origin angles local.newbot.angles targetname health
    			local.medkit.time = level.time
    			local.medkit set_respawn 0
    			local.medkit item_droptofloor
    			local.medkit.trigger = spawn trigger_multiple spawnflags 12
    			local.min = vector_subtract local.medkit.origin (24 24 24)
    			local.max = vector_add local.medkit.origin (24 24 24)
    			local.medkit.trigger setsize local.min local.max
    			local.medkit.trigger.medkit = local.medkit
    			local.medkit.trigger thread medkit_trigger
    			local.medkit.trigger thread remove 10
    			local.medkit thread remove 10
    		}
    	}
    	else
    	{
    		local.newbot notsolid
    		local.newbot hide
    		local.newbot thread remove 10
    	}
    end
    
    
    /**
    Sporadic bot taunting. Can be called by
    an external script.
    */
    killhappiness:
    	local.num = randomint 9
    
    	if(local.num == 0)
    		local.say = da
    	else if(local.num == 1)
    		local.say = db
    	else if(local.num == 2)
    		local.say = dc
    	else if(local.num == 3)
    		local.say = dd
    	else if(local.num == 4)
    		local.say = de
    	else if(local.num == 5)
    		local.say = df
    	else if(local.num == 6)
    		local.say = dg
    	else if(local.num == 7)
    		local.say = dh
    	else
    		local.say = di
    	// taunt
    
    
    	wait 1.5
    	if(isAlive self && self.enemy == NULL)
    		self thread level.jvbot_main_script::say local.say
    end
    
    
    saythanks local.other:
    	wait 1.5
    	if(isAlive self && isAlive local.other)
    	{
    		if(self cansee local.other 360 512)
    		{
    			local.sound = randomint 3
    			switch(local.sound)
    			{
    				case 0:
    					local.say = "cg"
    					break
    				case 1:
    					local.say = "ch"
    					break
    				default:
    					local.say = "ci"
    					break
    			}
    			self lookat local.other
    			wait 0.2
    			self waitthread level.jvbot_main_script::say local.say
    			wait 1
    			if(isAlive self)
    				self lookat NULL
    		}
    	}
    end
    
    
    
    
    /**
    Increases bot health when walking over a medkit.
    Only works for medkits dropped by dead bots.
    Internal use.
    */
    medkit_trigger:
    	self waittill trigger
    	while(self && self.medkit)
    	{
    		local.prev = parm.other.health
    		if(local.prev < 100) // can't heal a sound bot
    		{
    			parm.other.health += 50
    			if(parm.other.health > 100)
    				parm.other.health = 100
    			self.medkit remove
    			if(self)
    				self remove
    			break
    		}
    		waitframe
    		self waittill trigger
    	}
    end
    
    
    /**
    Removes the entity after the given delay.
    
    
    float delay: number of seconds to wait before removal.
    */
    remove local.delay:
    	wait local.delay
    
    	if(self)
    		self remove
    end
    
    
    /**
    Gets the correct index for actualbots array.
    This value is NOT equal to bot ID.
    Internal use.
    */
    getindex:
    	for(local.i = 1; local.i <= level.bots; local.i++)
    	{
    		if(level.actualbots[local.i] == NULL || level.actualbots[local.i] == NIL || !(isAlive level.actualbots[local.i]))
    			end local.i
    	}
    end level.bots
    
    
    /**
    Removes elements from actualbots array when the number
    of bots decreases. Bot IDs remain unaltered.
    Internal use.
    */
    setlastbotid:
    	for(local.i = level.botlastid; local.i >= 1; local.i--)
    	{
    		if(level.actualbots[local.i] == NULL || level.actualbots[local.i] == NIL || !(isAlive level.actualbots[local.i]))
    			level.botlastid--
    		else
    			break
    	}
    end
    
    
    /**
    Prints the current actualbots array to the console.
    For debug purposes only.
    */
    printbotarray:
    	println " "
    	println "BoT array"
    	println "=========="
    	for(local.i = 1; local.i <= level.actualbots.size; local.i++)
    	{
    		print "[" local.i "]: " level.actualbots[local.i]
    		if(level.actualbots[local.i] != NIL && level.actualbots[local.i] != NULL)
    		{
    			print " #" level.actualbots[local.i].entnum
    			if !(isAlive level.actualbots[local.i])
    				print " (dead)"
    		}
    		println
    		if(local.i == level.botlastid)
    			println "<------------------>"
    	}
    	println
    	println ""
    end
    
    
    /**
    Sets up the bot.
    */
    setgeneral:
    	self.targetname = "ai"
    	self.interval = 128 // test, prevents jams
    	self.nosurprise = 1
    	self.nolongpain = 1
    	self.enemysharerange = 1
    	self.hearing = 0
    ////////////////Sor's Fixes//////////////////////////
    	self.fixedleash = 0
    	self thread leasher
    /////////////////////////////////////////////////////
    	self.fov = 90
    	self.noticescale = 1
    	self.sound_awareness = 0
    
    	//* sets the bot to use a custom animation handler.
    	self.attackhandler = level.jvbot_attackhandler
    	//* overwrites default init handler
    	self.lastpaintime = -5
    	self.pain = 0
    	self thread setpainhandler
    
    	self.maxdist = self.sight
    	self.leash = self.mindist
    
    	if(level.debug_light == 1)
    		self thread level.jvbot_modscript[debug]::debughighlight
    end
    
    
    setpainhandler:
    	while(isAlive self)
    	{
    		self.painhandler = "anim/jv_bots/pain.scr"
    		waitframe
    	}
    end
    
    
    sneakshot:
    	if (self.cupdate != NIL){
    		local.cupdate_sneak = self.cupdate
    	}
    	else {
    		local.cupdate_sneak = 2000
    	}
    	// annoying quick reaction ;)
    	while(isAlive self)
    	{
    		if(self.enemy && isAlive self.enemy && level.jvbot_skill > 1)
    		{
    			if !(vector_within self.origin self.enemy.origin 200)
    			{
    				if(self cansee self.enemy 60 local.cupdate_sneak)
    				{
    					if(self ReadyToFire && self.inreload != 1)
    					{
    						self aimat self.enemy
    						wait 0.2
    						local.acc = self.accuracy
    						self.accuracy = level.jvbot_skill * 10
    						self fire
    						wait 0.1
    						self.accuracy = local.acc
    						self aimat NULL
    						while (isAlive self && isAlive self.enemy && self cansee self.enemy 60 local.cupdate_sneak)
    							wait 0.1
    					}
    				}
    			}
    		}
    		waitframe
    	}
    end
    
    
    /**
    Returns an array with the number of allies and
    axis team members (bots + players).
    local.team is an optional argument
    */
    getteammembers local.team local.botsonlyalive local.playersalsodead:
    	if(local.playersalsodead == 1)
    		local.players = $player
    	else
    		local.players = waitthread global/jv_mp_players.scr::get_active_players $player
    
    
    	switch(local.team)
    	{
    		allies:
    			local.alliesplayers = waitthread global/jv_mp_players.scr::get_team_players local.players allies
    			if(local.botsonlyalive != NIL)
    				local.bots = waitthread getnumaliveteambots allies
    			else
    				local.bots = level.teambots[allies]
    			local.output = local.alliesplayers.size + local.bots
    			break
    		axis:
    			local.axisplayers = waitthread global/jv_mp_players.scr::get_team_players local.players axis
    			if(local.botsonlyalive != NIL)
    				local.bots = waitthread getnumaliveteambots axis
    			else
    				local.bots = level.teambots[allies]
    			local.output = local.axisplayers.size + local.bots
    			break
    		default:
    			local.alliesplayers = waitthread global/jv_mp_players.scr::get_team_players local.players allies
    			local.axisplayers = waitthread global/jv_mp_players.scr::get_team_players local.players axis
    			if(local.botsonlyalive != NIL)
    			{
    				local.alliesbots = waitthread getnumaliveteambots allies
    				local.axisbots = waitthread getnumaliveteambots axis
    			}
    			else
    			{
    				local.alliesbots = level.teambots[allies]
    				local.axisbots = level.teambots[axis]
    			}
    			local.allies = local.alliesplayers.size + local.alliesbots
    			local.axis = local.axisplayers.size + local.axisbots
    			local.output = local.allies::local.axis
    	}
    end local.output
    
    
    getnumaliveteambots local.team:
    	local.num = 0
    	for(local.i = 1; local.i <= level.botlastid; local.i++)
    	{
    		local.bot = level.actualbots[local.i]
    		if(isAlive local.bot && local.bot.dmteam == local.team)
    			local.num++
    	}
    end local.num
    
    
    /**
    Returns the team with clearly fewer members.
    */
    geteventeam:
    	local.array = waitthread getteammembers
    	local.allies = local.array[1]
    	local.axis = local.array[2]
    	if(local.allies > local.axis)
    		local.team = axis
    	else if(local.axis > local.allies)
    		local.team = allies
    	else
    	{
    		if(randomint 2 == 0) // 0 or 1
    			local.team = allies
    		else
    			local.team = axis
    	}
    end local.team
    
    
    /**
    Returns a model as stored in the level.jvbot_<team>preset array,
    which was created based on $alliesspawnpreset and $axisspawnpreset
    entities in the bsp file.
    
    
    string team: allies or axis
    */
    getmodel local.team:
    	if(local.team == axis)
    		local.models = level.jvbot_axispreset
    	else
    		local.models = level.jvbot_alliespreset
    
    	local.num = randomint local.models.size + 1
    	local.model = local.models[local.num]
    end local.model
    
    
    /**
    Returns a spawn position for the corresponding team.
    
    
    string team: 	allies or axis
    bool noretry:	don't try opposing spawn if no spawn pos is found.
    */
    getspawnposition local.team local.noretry:
    	local.spawnposlist = $(local.team + "spawn")
    	// find enabled spawn positions
    	local.j = 1
    	for(local.i = 1; local.i <= local.spawnposlist.size; local.i++)
    	{
    		local.posspawnpos = local.spawnposlist[local.i]
    		if(local.posspawnpos.disablespawn != 1)
    		{
    			local.posspawnposlist[local.j] = local.posspawnpos
    			local.j++
    		}
    	}
    	if !(local.posspawnposlist.size > 0)
    	{
    		if(local.team == allies)
    			local.opp_team = axis
    		else
    			local.opp_team = allies
    
    		if(local.noretry == NIL)
    		{
    			println "ERROR[spawnhandler_default::getspawnposition]: Cannot find a spawn position for team " local.team ", trying " local.opp_team
    			local.spawnpos = waitthread getspawnposition local.opp_team 1
    		}
    		else
    		{
    			println "ERROR[spawnhandler_default::getspawnposition]: Couldn't find a spawn position, using (0 0 0)."
    			if !($centerspawn)
    				local.spawnpos = spawn script_origin targetname "centerspawn" origin (0 0 0)
    			else
    				local.spawnpos = $centerspawn
    		}
    	}
    	else
    	{
    		local.k = 0
    		local.j = 0
    		while(local.k <= 0)
    		{
    			// order spawn positions by user groups
    			// start with users = 0 or NIL
    			for(local.i = 1; local.i <= local.posspawnposlist.size; local.i++)
    			{
    				local.pos = local.posspawnposlist[local.i]
    				if(local.pos.users == NIL)
    					local.pos.users = 0
    				if(local.pos.users <= local.j)
    				{
    					local.k ++
    					local.orderedspawnposlist[local.k] = local.pos
    				}
    			}
    			// clean up array
    			local.j++
    			// not necessary anymore
    			//local.posspawnposlist = waitthread subtractarrays local.posspawnposlist local.orderedspawnposlist
    		}
    		local.num = randomint(local.orderedspawnposlist.size) + 1
    		local.spawnpos = local.orderedspawnposlist[local.num]
    	}
    	local.spawnpos.users++
    	local.spawnpos thread decreaseusers 2 // give time to get away
    end local.spawnpos
    
    
    decreaseusers local.delay:
    	wait local.delay
    	self.users--
    end
    
    
    subtractarrays local.a local.b:
    	// removes all entries of b from a
    	local.k = 0
    	for(local.i = 1; local.i <= local.a.size; local.i++)
    	{
    		local.a_entry = local.a[local.i]
    		// check if this entry exists in b
    		local.in_b = 0
    		for(local.j = 1; local.j <= local.b.size; local.b++)
    		{
    			local.b_entry = local.b[local.j]
    			if(local.a_entry == local.b_entry)
    			{
    				local.in_b = 1
    				break
    			}
    		}
    		if(local.in_b == 0)
    		{
    			local.k++
    			local.out[local.k] = local.a_entry
    		}
    	}
    end local.out
    
    
    ////////////////Sor's Fixes//////////////////////////
    leasher:
    
    
    	// todo: set a level variable to enable and disable the resetting of leashes.
    	while(isAlive self)
    	{
    		self resetleash
    		wait 1
    	}
    end
    //////////////////////////////////////////////////////
    Last edited by Sor; April 16th, 2015 at 08:01 AM.
    Morpheus Script (MoH) => You try to shoot yourself in the foot only to discover that MorpheusScript already shot your foot for you.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •